package com.sukaiyi.generator.ui;

import com.sukaiyi.generator.config.model.StructTemplate;
import com.sukaiyi.generator.config.model.TplType;
import com.sukaiyi.generator.config.utils.TemplateUtils;
import com.sukaiyi.generator.ui.base.ConfirmationDialog;
import com.sukaiyi.generator.ui.base.InputChooseDialog;
import com.sukaiyi.generator.ui.base.InputDialog;
import com.sukaiyi.generator.ui.renderer.TemplateTreeNodeRenderer;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.*;
import com.intellij.ui.treeStructure.Tree;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.*;
import java.awt.*;
import java.util.Enumeration;
import java.util.Objects;

public class TemplateTree {
    private JPanel rootPanel;
    private Tree tree;
    private TreeNodeDeleteListener treeNodeDeleteListener;

    public TemplateTree() {
        DefaultActionGroup actionGroup = createActionGroup();
        ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar("Group Toolbar", actionGroup, true);
        rootPanel.add(actionToolbar.getComponent(), BorderLayout.NORTH);
    }

    private void createUIComponents() {
        tree = new Tree();
        tree.setEditable(true);
        tree.setCellRenderer(new TemplateTreeNodeRenderer());
    }

    public void setStructTemplate(StructTemplate template) {
        if (template != null) {
            tree.setModel(new DefaultTreeModel(TemplateUtils.toTreeNode(template)));
            TreeNode root = (TreeNode) tree.getModel().getRoot();
            TreePath rootPath = new TreePath(root);
            expandAll(rootPath, true);
        } else {
            tree.setModel(new DefaultTreeModel(null));
        }
    }

    public StructTemplate getStructTemplate() {
        DefaultTreeModel treeModel = (DefaultTreeModel) tree.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) treeModel.getRoot();
        return TemplateUtils.toStructTemplate(root);
    }

    public void addTreeSelectionListener(TreeSelectionListener listener) {
        tree.addTreeSelectionListener(listener);
    }

    public void addTreeNodeDeleteListener(TreeNodeDeleteListener listener) {
        this.treeNodeDeleteListener = listener;
    }

    public void expandAll(TreePath treePath, boolean expand) {
        TreeNode node = (TreeNode) treePath.getLastPathComponent();
        if (node.getChildCount() >= 0) {
            for (Enumeration e = node.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode) e.nextElement();
                TreePath path = treePath.pathByAddingChild(n);
                expandAll(path, expand);
            }
        }
        if (expand) {
            tree.expandPath(treePath);
        } else {
            tree.collapsePath(treePath);
        }
    }

    public TreeNode getFirstLeaf(TreeNode rootNode) {
        if (rootNode.isLeaf()) {
            return rootNode;
        }
        if (rootNode.getChildCount() >= 0) {
            for (Enumeration e = rootNode.children(); e.hasMoreElements(); ) {
                TreeNode n = (TreeNode) e.nextElement();
                TreeNode firstLeaf = getFirstLeaf(n);
                if (firstLeaf != null) {
                    return firstLeaf;
                }
            }
        }
        return null;
    }

    public JComponent get() {
        return rootPanel;
    }

    public void removeAll() {
        tree.removeAll();
    }

    private DefaultActionGroup createActionGroup() {
        DefaultActionGroup actionGroup = new DefaultActionGroup();
        actionGroup.add(new AnAction(AllIcons.General.Add) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (selectedNode == null) return;
                InputChooseDialog dialog = new InputChooseDialog(new String[]{"Directory", "File"});
                if (dialog.showAndGet()) {
                    InputChooseDialog.NodeInfo nodeInfo = dialog.getValue();
                    StructTemplate tpl = new StructTemplate(nodeInfo.getName(), "", Objects.equals("File", nodeInfo.getType()) ? TplType.TEMPLATE : TplType.MODULE, null);
                    DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(tpl);
                    selectedNode.add(newNode);
                    tree.updateUI();
                }
            }
        });
        actionGroup.add(new AnAction(AllIcons.Actions.Edit) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
                if (node == null) {
                    return;
                }
                StructTemplate template = (StructTemplate) node.getUserObject();
                InputDialog dialog = new InputDialog(template.getName());
                boolean flag = dialog.showAndGet();
                if (flag) {
                    String newName = dialog.getValue();
                    template.setName(newName);
                    tree.updateUI();
                }
            }
        });
        actionGroup.add(new AnAction(AllIcons.General.Remove) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                MutableTreeNode[] nodes = tree.getSelectedNodes(MutableTreeNode.class, v -> true);
                if (nodes.length <= 0) {
                    return;
                }
                ConfirmationDialog dialog = new ConfirmationDialog();
                if (dialog.showAndGet()) {
                    for (MutableTreeNode node : nodes) {
                        if (node != null && node.getParent() != null) {
                            ((DefaultTreeModel) tree.getModel()).removeNodeFromParent(node);
                        }
                    }
                    if (treeNodeDeleteListener != null) {
                        treeNodeDeleteListener.onDelete(nodes);
                    }
                }
            }
        });
        actionGroup.addSeparator();
        actionGroup.add(new AnAction(AllIcons.Actions.Expandall) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                TreeNode root = (TreeNode) tree.getModel().getRoot();
                TreePath rootPath = new TreePath(root);
                expandAll(rootPath, true);
            }
        });
        actionGroup.add(new AnAction(AllIcons.Actions.Collapseall) {
            @Override
            public void actionPerformed(@NotNull AnActionEvent e) {
                TreeNode root = (TreeNode) tree.getModel().getRoot();
                TreePath rootPath = new TreePath(root);
                expandAll(rootPath, false);
            }
        });
        return actionGroup;
    }

}
